﻿/*************************************************
taurus Socket核心基类
author：Daixiwei
**************************************************/
using System;
using System.Net;
using System.Net.Sockets;

namespace taurus.client
{

    public enum SocketState
    {
        Disconnected,
        Connecting,
        Connected,
        Disconnecting
    }

    
    public abstract class ISocket
    {
        internal SocketEngine _engine;

        /// <summary>
        /// 当前socket状态
        /// </summary>
        public SocketState state = SocketState.Disconnected;

        /// <summary>
        /// 服务器地址
        /// </summary>
        protected string serverAddress;
        /// <summary>
        /// 服务器端口
        /// </summary>
        protected int serverPort;

        public ISocket(SocketEngine peerBase)
        {
            if (peerBase == null)
            {
                throw new Exception("Can't init without peer");
            }
            this._engine = peerBase;
        }

        /// <summary>
        /// 网络链接状态
        /// </summary>
        /// <returns></returns>
        public bool isConnected()
        {
            return state == SocketState.Connected;
        }

        public virtual bool connect()
        {
            bool result;
            string serverAddress;
            ushort serverPort;
            if (state != SocketState.Disconnected)
            {
                Logger.error("Calling connect when the socket is not disconnected");
                result = false;
            }
            else if (_engine == null)
            {
                result = false;
            }
            else if (!tryParseAddress(_engine.getServerAddress(), out serverAddress, out serverPort))
            {
                Logger.error("Failed parsing address: " + _engine.getServerAddress());
                result = false;
            }
            else
            {
                this.serverAddress = serverAddress;
                this.serverPort = (int)serverPort;
                result = true;
            }
            return result;
        }

        public abstract bool disconnect();

        public abstract bool send(byte[] data);
        
        

        protected internal void handleException(SocketCode statusCode)
        {
            state = SocketState.Disconnecting;
            _engine.enqueueStatusCallback(statusCode);
            _engine.enqueueActionForDispatch(delegate
            {
                disconnect();
            });
        }

        /// <summary>
        /// 解析网络地址
        /// </summary>
        /// <param name="addressAndPort"></param>
        /// <param name="address"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        protected internal bool tryParseAddress(string addressAndPort, out string address, out ushort port)
        {
            address = string.Empty;
            port = 0;
            bool result;
            if (string.IsNullOrEmpty(addressAndPort))
            {
                result = false;
            }
            else
            {
                int num = addressAndPort.LastIndexOf(':');
                if (num <= 0)
                {
                    result = false;
                }
                else if (addressAndPort.IndexOf(':') != num && (!addressAndPort.Contains("[") || !addressAndPort.Contains("]")))
                {
                    result = false;
                }
                else
                {
                    address = addressAndPort.Substring(0, num);
                    var s = addressAndPort.Substring(num + 1);
                    var flag = ushort.TryParse(s, out port);
                    result = flag;
                }
            }
            return result;
        }

        /// <summary>
        /// 获取IP地址
        /// </summary>
        /// <param name="serverIp"></param>
        /// <returns></returns>
        protected internal static IPAddress getIpAddress(string serverIp)
        {
            IPAddress iPAddress = null;
            IPAddress result;
            if (IPAddress.TryParse(serverIp, out iPAddress))
            {
                result = iPAddress;
            }
            else
            {
                IPHostEntry hostEntry = Dns.GetHostEntry(serverIp);
                IPAddress[] addressList = hostEntry.AddressList;
                IPAddress[] array = addressList;
                for (int i = 0; i < array.Length; i++)
                {
                    IPAddress iPAddress2 = array[i];
                    if (iPAddress2.AddressFamily == AddressFamily.InterNetwork)
                    {
                        result = iPAddress2;
                        return result;
                    }
                }
                array = addressList;
                for (int i = 0; i < array.Length; i++)
                {
                    IPAddress iPAddress2 = array[i];
                    if (iPAddress2.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        result = iPAddress2;
                        return result;
                    }
                }
                result = null;
            }
            return result;
        }
    }
}
